#include "Parser.h"

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  Parser
 * Description:  Contrói um Parser
 *--------------------------------------------------------------------------------------
 */
Parser::Parser(const string &filename)
    : ifs(filename.c_str())
{
    bpointer = bsize = 0;
    read();
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  read
 * Description:  Lê um caracter
 *--------------------------------------------------------------------------------------
 */
char Parser::read()
{
    // Caso tenha atingido o fim do buffer
    if(bpointer == bsize)
    {
        // Se encontrou final de arquivo, retorna 0
        if(ifs.eof())
            return 0;

        // Lê mais caracteres do arquivo e coloca no buffer
        ifs.read(buffer, READ_SIZE);
        bsize = ifs.gcount();
        bpointer = 0;
    }

    // Retorna o caracter no buffer apontado por bpointer
    return buffer[bpointer++];
}

/*--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  parse
 * Description:  Realiza o parseamento
 *--------------------------------------------------------------------------------------
 */
Dictionary& Parser::parse()
{
    char state = SKIP_BEFORE;
    string word;
    char c;

    // Lê enquanto ainda tem caracteres disponíveis
    while((c = read()) != 0)
    {
        switch(state)
        {
            // Estado que pula os espaços antes de iniciar uma palavra
            case SKIP_BEFORE:
                if(isalpha(c))
                    word.clear(), word += tolower(c), state = APPEND_CHAR;
                break;

            // Estado que concatena os caracteres para formar uma palavra
            case APPEND_CHAR:
                if(isalpha(c))
                    word += tolower(c);
                else if(isseparator(c))
                    dict.add(word), state = SKIP_BEFORE;
                else
                    state = SKIP_AFTER;
                break;

            // Estado que pula os espaços depois de terminar uma palavra
            case SKIP_AFTER:
                if(isalpha(c))
                    state = SKIP_WORD;
                else if(isseparator(c))
                    dict.add(word), state = SKIP_BEFORE;
                break;

            // Estado que pula a palavra atual, pois é composta
            case SKIP_WORD:
                if(isseparator(c))
                    state = SKIP_BEFORE;
                break;
        }
    }

    // Se a palavra atual conter algo, a adiciona
    if(word.length() >= 1)
        dict.add(word);

    return dict;
}

/*--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  getDictionary
 * Description:  Retorna as palavras encontradas
 *--------------------------------------------------------------------------------------
 */
Dictionary& Parser::getDictionary()
{
    return dict;
}

/*--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  isseparator
 * Description:  Verifica se determinado caracter c é separador
 *--------------------------------------------------------------------------------------
 */
inline bool Parser::isseparator(char c)
{
    return (c == ',' || c == '\r' || c == '\n');
}
